﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using AdventureWorksData.DAO;
using AdventureWorks.Entities;
using AdventureWorks.Helpers;
using System.Web;
using AdventureWorks.Exceptions;

namespace AdventureWorks.Business
{
	public class ProductBusiness : IBusiness<Product>, IDisposable
	{
		private readonly IUnitOfWork _db;
		private IEnumerable<Product> _products;
		
		
		public ProductBusiness()
		{
			_db = new UnitOfWork();
		}

		public ProductBusiness(IUnitOfWork entityDb)
		{
			this._db = entityDb;
		}

		public Product Get(int id)
		{
			return _db.Products.Get(id);
		}

		public IEnumerable<Product> GetList(ProductFilter productFilter)
		{
			_products = GetList(productFilter.SortOrder, productFilter.SearchString);

			if(productFilter.ProductCategoryID != 0)
				_products = _products.Where(p => p.ProductCategoryID == productFilter.ProductCategoryID);

			if(productFilter.ProductModelID != 0)
				_products = _products.Where(p => p.ProductModelID == productFilter.ProductModelID);

			return _products;
		}

		public IEnumerable<Product> GetList(String sortOrder, String searchString)
		{
			_products = _db.Products.Get();
			FilterWithSearchString(searchString);
			SortOrder(sortOrder);
			
			return _products;
		}

		private void FilterWithSearchString(String searchString)
		{
			if (!String.IsNullOrEmpty(searchString))
			{
				_products = _products.Where(p =>
					CustomComparer.CompareString(
						new String[] { p.ID.ToString(), p.Name, p.ProductNumber, p.ProductCategory.Name, p.ProductModel.Name },
						searchString));
			}
		}

		private void SortOrder(String sortOrder)
		{
			switch (sortOrder)
			{
				case "Name Desc":
					_products = _products.OrderByDescending(p => p.Name);
					break;
				case "Cost":
					_products = _products.OrderBy(p => p.StandardCost);
					break;
				case "Cost Desc":
					_products = _products.OrderByDescending(p => p.StandardCost);
					break;
				case "Price":
					_products = _products.OrderBy(p => p.ListPrice);
					break;
				case "Price Desc":
					_products = _products.OrderByDescending(p => p.ListPrice);
					break;
				case "Weight":
					_products = _products.OrderBy(p => p.Weight);
					break;
				case "Weight Desc":
					_products = _products.OrderByDescending(p => p.Weight);
					break;
				case "Modified":
					_products = _products.OrderBy(p => p.ModifiedDate);
					break;
				case "Modified Desc":
					_products = _products.OrderByDescending(p => p.ModifiedDate);
					break;
				default:
					_products = _products.OrderBy(p => p.Name);
					break;
			}
		}

		public Product Format(Product product, int productCategoryID, int productModelID, HttpPostedFileBase thumbNailPhotoImage, Byte[] thumbNailPhotoOld)
		{
			if (thumbNailPhotoImage != null)
			{
				product.ThumbnailPhotoFileName = thumbNailPhotoImage.FileName;
				product.ThumbNailPhoto = ProductHelper.GetThumb(thumbNailPhotoImage);
			}
			else
			{
				product.ThumbNailPhoto = thumbNailPhotoOld;
			}
			return Format(product, productCategoryID, productModelID);
		}

		public Product Format(Product product, int productCategoryID, int productModelID)
		{
			product.ProductCategoryID = productCategoryID;
			product.ProductCategory = _db.ProductCategories.Get(productCategoryID);

			product.ProductModelID = productModelID;
			product.ProductModel = _db.ProductModels.Get(productModelID);

			if (product.Validate())
			{
				return product;
			}
			else
			{
				ThrowInvalidException();
				return null;
			}
		}

		public void Insert(Product entity)
		{
			if (entity.Validate())
			{
				_db.Products.Insert(entity);
			}
			else
			{
				ThrowInvalidException();
			}
		}

		public void Update(Product entity)
		{
			entity.ModifiedDate = DateTime.Now;
			if (entity.Validate())
			{
				_db.Products.Update(entity);
			}
			else
			{
				ThrowInvalidException();
			}
		}

		public void Delete(int id)
		{
			_db.Products.Delete(id);
		}

		public void Save()
		{
			_db.Save();
		}

		public void Dispose()
		{
			_db.Dispose();
		}


		public void ThrowInvalidException()
		{
			throw new BusinessException("Invalid Product");
		}
	}
}
